////////////////////////////////////////////////////////////////////////////
//
//
//    Project     : VideoNet version 1.1.
//    Description : Peer to Peer Video Conferencing over the LAN.
//	  Author      :	Nagareshwar Y Talekar ( nsry2002@yahoo.co.in)
//    Date        : 15-6-2004.
//
//
//    File description : 
//    Name    : convert.cpp
//    Details : Conversion routine from RGB24 to YUV420 & YUV420 to RGB24.
//
/////////////////////////////////////////////////////////////////////////////


#include "convert.h"

static int RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static int RGBYUV01684[256], RGBYUV03316[256];
static int RGBYUV04187[256], RGBYUV00813[256];

// Conversion from YUV420 to RGB24
static long int crv_tab[256];
static long int cbu_tab[256];
static long int cgu_tab[256];
static long int cgv_tab[256];
static long int tab_76309[256];
static unsigned char clp[1024];			//for clip in CCIR601
unsigned char *clp1;

void init_rgb2yuv()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV02990[i] = (int)(0.2990 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (int)(0.5870 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (int)(0.1140 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV01684[i] = -(int)(0.1684 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV03316[i] = -(int)(0.3316 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV04187[i] = -(int)(0.4187 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV00813[i] = -(int)(0.0813 * i * 65536);
}

void getyuvtorgbtable()
{	
	long int crv,cbu,cgu,cgv;
	int i;  

	clp1 = clp + 384;

	for (i=-384; i<640; i++){
		clp1[i] = (i<0) ? 0 : ((i>255) ? 255 : i);
	}
	
	crv = 104597; cbu = 132201;
	cgu = 25675;  cgv = 53279;

	for (i = 0; i < 256; i++) {
		crv_tab[i] = (i-128) * crv;
		cbu_tab[i] = (i-128) * cbu;
		cgu_tab[i] = (i-128) * cgu;
		cgv_tab[i] = (i-128) * cgv;
		tab_76309[i] = 76309*(i-16);
	}
}

void ConvertYUVtoRGB(unsigned char *yuv,unsigned char *dst_ori,int width, int height)
{
   int y11,y21;
   int y12,y22;
   int y13,y23;
   int y14,y24;
   int u,v; 
   int i,j;
   int c11, c21, c31, c41;
   int c12, c22, c32, c42;
   unsigned int DW;
   unsigned int *id1, *id2;
   unsigned char *py1,*py2,*pu,*pv;
   unsigned char *d1, *d2;

   d1 = dst_ori;
   d1 += width*height*3 - width*3;
   d2 = d1 - width*3;
   
   py1 = yuv; 
   pu  = yuv+width*height; 
   pv  = yuv + (width*height+(width*height)/4);//lbx
   
   py2 = py1 + width;
   
   id1 = (unsigned int *)d1;
   id2 = (unsigned int *)d2;

   for (j = 0; j < height; j += 2) 
   { 
      for (i = 0; i < width; i += 4) 
	  {
         u = *pu++;
         v = *pv++;
         c11 = crv_tab[v];
         c21 = cgu_tab[u];
         c31 = cgv_tab[v];
         c41 = cbu_tab[u];
         u = *pu++;
         v = *pv++;
         c12 = crv_tab[v];
         c22 = cgu_tab[u];
         c32 = cgv_tab[v];
         c42 = cbu_tab[u];

         y11 = tab_76309[*py1++]; // (255/219)*65536 
         y12 = tab_76309[*py1++];
         y13 = tab_76309[*py1++]; // (255/219)*65536 
         y14 = tab_76309[*py1++];

         y21 = tab_76309[*py2++];
         y22 = tab_76309[*py2++];
         y23 = tab_76309[*py2++];
         y24 = tab_76309[*py2++];

         // RGBR
         DW = ((clp1[(y11 + c41)>>16])) |
            ((clp1[(y11 - c21 - c31)>>16])<<8) |
            ((clp1[(y11 + c11)>>16])<<16) |  
            ((clp1[(y12 + c41)>>16])<<24);
         *id1++ = DW;

         // GBRG
         DW = ((clp1[(y12 - c21 - c31)>>16])) |
            ((clp1[(y12 + c11)>>16])<<8) |  
            ((clp1[(y13 + c42)>>16])<<16) |
            ((clp1[(y13 - c22 - c32)>>16])<<24);
         *id1++ = DW;

         // BRGB
         DW = ((clp1[(y13 + c12)>>16])) |  
            ((clp1[(y14 + c42)>>16])<<8) |
            ((clp1[(y14 - c22 - c32)>>16])<<16) |
            ((clp1[(y14 + c12)>>16])<<24);  
         *id1++ = DW;

         // RGBR
         DW = ((clp1[(y21 + c41)>>16])) |
            ((clp1[(y21 - c21 - c31)>>16])<<8) |
            ((clp1[(y21 + c11)>>16])<<16) |  
            ((clp1[(y22 + c41)>>16])<<24);
         *id2++ = DW;

         // GBRG
         DW = ((clp1[(y22 - c21 - c31)>>16])) |
            ((clp1[(y22 + c11)>>16])<<8) |  
            ((clp1[(y23 + c42)>>16])<<16) |
            ((clp1[(y23 - c22 - c32)>>16])<<24);
         *id2++ = DW;

         // BRGB
         DW = ((clp1[(y23 + c12)>>16])) |  
            ((clp1[(y24 + c42)>>16])<<8) |
            ((clp1[(y24 - c22 - c32)>>16])<<16) |
            ((clp1[(y24 + c12)>>16])<<24);  
         *id2++ = DW;
      }
      id1 -= (9 * width)>>2;
      id2 -= (9 * width)>>2;
      py1 += width;
      py2 += width;
   }
   
} 